package com.heaven.config;

import com.heaven.exception.BizCodeEnum;
import com.heaven.exception.RRException;
import com.heaven.utils.ThreadUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.List;
import java.util.concurrent.*;

/**
 * 线程池配置
 *
 * @author ruoyi
 **/
@Configuration
@Slf4j
public class ThreadPoolConfig
{
    // 核心线程池大小
    private final int corePoolSize = 50;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);

        // 最大可创建的线程数
        int maxPoolSize = 400;
        executor.setMaxPoolSize(maxPoolSize);
        // 队列最大长度
        int queueCapacity = 1000;
        executor.setQueueCapacity(queueCapacity);
        // 线程池维护线程所允许的空闲时间（ms）
        int keepAliveSeconds = 300;
        executor.setKeepAliveSeconds(keepAliveSeconds);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务的线程池
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService()
    {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy())
        {
            @Override
            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);
                ThreadUtils.printException(r, t);
            }
        };
    }



    /**
     * 阻塞异步任务直至全部执行完成, 并清除掉任务列表的所有任务
     * @param tasks 没有返回值的异步任务
     */
    public static void blockTask(List<CompletableFuture<Void>> tasks) {
        CompletableFuture<Void> combine = CompletableFuture.allOf(tasks.toArray(new CompletableFuture[0]));
        try {
            combine.get();
            tasks.clear();
        } catch (InterruptedException | ExecutionException e) {
            log.error(BizCodeEnum.THREAD_EXCEPTION.getMsg()+"合并线程任务异常");
            if(e instanceof InterruptedException){
                Thread.currentThread().interrupt();
                throw new RRException(BizCodeEnum.THREAD_EXCEPTION, "线程被中断", e);
            } else {
                Throwable cause = e.getCause();
                throw new RRException(BizCodeEnum.THREAD_EXCEPTION, "线程执行过程中的异常", cause);
            }
        }
    }
}
